package com.gateway.plugin.tenant;

import com.gateway.common.dto.RuleData;
import com.gateway.common.dto.SelectorData;
import com.gateway.common.dto.convert.rule.impl.TenantRuleHandle;
import com.gateway.common.enums.PluginEnum;
import com.gateway.common.exception.ThrowingFunction;
import com.gateway.plugin.api.GatewayPluginChain;
import com.gateway.plugin.api.result.GatewayResultEnum;
import com.gateway.plugin.api.result.GatewayResultWrap;
import com.gateway.plugin.api.util.WebFluxResultUtils;
import com.gateway.plugin.base.AbstractGatewayPlugin;
import com.gateway.plugin.base.util.CacheKeyUtils;
import com.gateway.plugin.tenant.handle.TenantPluginDataHandler;
import com.gateway.plugin.tenant.strategy.JwtConvertStrategy;
import com.gateway.plugin.tenant.strategy.JwtConvertStrategyFactory;
import com.google.common.collect.ImmutableMap;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.JwtParserBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @program: api-gateway
 * @description:
 * @author: YuKai Fan
 * @create: 2025/2/14 09:55
 **/
public class CnameTenantGatewayPlugin extends AbstractGatewayPlugin {

    /**
     * 既然可以走到此插件，说明规则判断cname域名匹配成功，所以此处可以获取到rule
     * @param exchange exchange the current server exchange {@linkplain ServerWebExchange}
     * @param chain    chain the current chain  {@linkplain ServerWebExchange}
     * @param selector selector    {@linkplain SelectorData}
     * @param rule     rule    {@linkplain RuleData}
     * @return
     */
    @Override
    protected Mono<Void> doExecute(ServerWebExchange exchange, GatewayPluginChain chain, SelectorData selector, RuleData rule) {
        if (Objects.isNull(rule)) {
            Object error = GatewayResultWrap.error(exchange, GatewayResultEnum.RULE_NOT_FOUND);
            return WebFluxResultUtils.result(exchange, error);
        }
        if (StringUtils.isBlank(rule.getHandle())) {
            Object error = GatewayResultWrap.error(exchange, GatewayResultEnum.RULE_NOT_FOUND);
            return WebFluxResultUtils.result(exchange, error);
        }
        TenantRuleHandle tenantRuleHandle = TenantPluginDataHandler.CACHE_HANDLE.get().obtainHandle(CacheKeyUtils.INST.getKey(rule));
        if (Boolean.TRUE.equals(tenantRuleHandle.getTenantDisable())) {
            Object error = GatewayResultWrap.error(exchange, GatewayResultEnum.TENANT_DISABLE);
            return WebFluxResultUtils.result(exchange, error);
        }
        if (Boolean.TRUE.equals(tenantRuleHandle.getAppDisable())) {
            Object error = GatewayResultWrap.error(exchange, GatewayResultEnum.APP_DISABLE);
            return WebFluxResultUtils.result(exchange, error);
        }
        return chain.execute(executeRuleHandle(tenantRuleHandle, exchange, Collections.emptyMap()));
    }

    @Override
    public int getOrder() {
        return PluginEnum.TENANT_CNAME.getCode();
    }

    @Override
    public String named() {
        return PluginEnum.TENANT_CNAME.getName();
    }

    private ServerWebExchange executeRuleHandle(final TenantRuleHandle tenantRuleHandle, final ServerWebExchange exchange, final Map<String, Object> jwtBody) {
        JwtConvertStrategy jwtConvertStrategy = JwtConvertStrategyFactory.newInstance(tenantRuleHandle.getHandleType());
        return jwtConvertStrategy.convert(tenantRuleHandle, exchange, jwtBody);
    }
}
